﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Common.Model;
using log4net;
using Microsoft.Win32;
using Newtonsoft.Json;

namespace Spider.Spider
{
    class RtnCloseSpider
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(RtnCloseSpider));
        private static string cookie="";


        /// <summary>
        /// 单个原因
        /// </summary>
        /// <param name="stockid"></param>
        /// <returns></returns>
        public static List<RtnCloseReason> UpedDetailStockbyId(string stockid)
        {
            string strrtn = "";
            try
            {
                string link = "http://www.iwencai.com/diag/block-detail?pid=11657&codes=" + stockid +
                              "&codeType=stock&info=%7B%22view%22%3A%7B%22nolazy%22%3A1%2C%22parseArr%22%3A%7B%22_v%22%3A%22new%22%2C%22dateRange%22%3A%5B%2220180312%22%2C%2220180312%22%5D%2C%22staying%22%3A%5B%5D%2C%22queryCompare%22%3A%5B%5D%2C%22comparesOfIndex%22%3A%5B%5D%7D%2C%22asyncParams%22%3A%7B%22tid%22%3A9381%7D%7D%7D";

                strrtn = GetRequest(link);

                for (int i = 0; i < 10 && strrtn.Contains("<html><body>"); i++)
                {
                    if (i > 8)
                    {
                        Log.Error("repeat time = " + i + "\nlink=" + link + "\nhtml=" + strrtn);
                    }
                    var match = Regex.Match(strrtn, "window\\.location\\.href=\"([^\"]*?)\"");
                    link = match.Groups[1].Value;
                    strrtn = GetRequest(link);
                }
                var xdx = JsonToObject<Root>(strrtn);
                if (xdx.data == null) return new List<RtnCloseReason>();
                var rtn = new List<RtnCloseReason>();
                foreach (var kk in xdx.data.data.result)
                {
                    if (kk.detail == null)
                    {
                        var temp = UpedDetailByLink(kk.detailApi, "", "");
                        temp.Stkcode = stockid;
                        temp.Keyword = kk.keyword;
                        temp.CrawlingTime = DateTime.Now;
                        temp.SiteTime = DateTime.Parse(kk.value);
                        rtn.Add(temp);
                    }
                    else
                        rtn.Add(new RtnCloseReason
                        {
                            Type = 0,
                            CrawlingTime = DateTime.Now,
                            Stkcode = stockid,
                            SiteTime = DateTime.Parse(kk.value),
                            Detial = kk.detail.@abstract,
                            Keyword = kk.keyword,
                            Link = kk.detail.url,
                            Title = kk.detail.title
                        });
                }
                return rtn;
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                return null;
            }
        }

        public static RtnCloseReason UpedDetailByLink(string link, string stkcode, string date)
        {
            try
            {
                if (link == "")
                {
                    link = @"http://www.iwencai.com/diag/search-ztreason?code=" + stkcode + "&date=" + date + "&tiny=1";
                }
                else
                {
                    link = "http://www.iwencai.com" + link;
                }
                string strrtn = GetRequest(link);
                Rootreason xdx = JsonToObject<Rootreason>(strrtn);
                Log.Info(stkcode + @" Done");
                return new RtnCloseReason
                {
                    Stkcode = stkcode,
                    Detial = xdx.data.@abstract,
                    Title = RemoveHtmlTag(xdx.data.title),
                    Link = xdx.data.url
                };
            }
            catch (Exception ex)
            {
                Log.Error(stkcode + link + "失败" + ex.Message);
                return null;
            }
        }

        /// <summary>
        /// 多个原因
        /// </summary>
        /// <param name="date"></param>
        /// <param name="stockid"></param>
        /// <returns></returns>
        //public static List<RtnCloseReason> UpedDetailRtbyjson(string date, string stockid)
        //{
        //    try
        //    {
        //        string link = "http://www.iwencai.com/diag/block-detail?pid=11656&codes=" + stockid +
        //                      "&codeType=stock&info=%7B%22view%22%3A%7B%22nolazy%22%3A1%2C%22parseArr%22%3A%7B%22_v%22%3A%22new%22%2C%22dateRange%22%3A%5B%22" +
        //                      date + "%22%2C%22" + date + "%22%5D%2C%22" +
        //                      "staying%22%3A%5B%5D%2C%22queryCompare%22%3A%5B%5D%2C%22comparesOfIndex%22%3A%5B%5D%7D%2C%22asyncParams%22%3A%7B%22tid%22%3A9381%7D%7D%7D";
        //        string strrtn = GetRequest(link);

        //        for (int i = 0; i < 10 && strrtn.Contains("<html><body>"); i++)
        //        {
        //            if (i > 8)
        //            {
        //                Log.Error("repeat time = " + i + "\nlink=" + link + "\nhtml=" + strrtn);
        //            }
        //            var match = Regex.Match(strrtn, "window\\.location\\.href=\"([^\"]*?)\"");
        //            link = match.Groups[1].Value;
        //            strrtn = GetRequest(link);
        //        }

        //        //问财在返回 extra的时候 带"{}"导致出错
        //        var begin = strrtn.IndexOf("\"extra\":\"{", StringComparison.Ordinal);
        //        if (begin != -1)
        //        {
        //            var end = strrtn.IndexOf("}\"", StringComparison.Ordinal) + 3;
        //            strrtn = strrtn.Remove(begin, end - begin);
        //        }
        //        var xdx = JsonToObject<Root11656>(strrtn);
        //        if (xdx.data == null) return new List<RtnCloseReason>();
        //        var rtn = new List<RtnCloseReason>();
        //        foreach (var kk in xdx.data.data.result.reasons)
        //        {
        //            rtn.Add(new RtnCloseReason
        //            {
        //                Stkcode = stockid,
        //                SiteTime = DateTime.Parse(date),
        //                Detial = RemoveHtmlTag(kk.@abstract),
        //                Keyword = kk.word ?? "",
        //                Link = kk.url,
        //                Title = RemoveHtmlTag(kk.title),
        //                Type = 1,
        //                CrawlingTime = DateTime.Now
        //            });
        //        }
        //        return rtn;
        //    }
        //    catch (Exception ex)
        //    {
        //        Log.Info(ex.Message);
        //        return null;
        //    }
        //}
        public static List<RtnCloseReason> UpedDetailRtbyjson(string date, string stockid)
        {
            try
            {
                stockid = stockid.Substring(0, 6);
                string link = "http://www.iwencai.com/diag/block-detail?pid=11656&codes=" + stockid +
                              "&codeType=stock&info=%7B\"view\"%3A%7B\"nolazy\"%3A1%2C\"parseArr\"%3A%7B\"_v\"%3A\"new\"%2C\"dateRange\"%3A%5B\"" + date + "\"%2C\"" + date +
                              "\"%5D%2C\"staying\"%3A%5B%5D%2C\"queryCompare\"%3A%5B%5D%2C\"comparesOfIndex\"%3A%5B%5D%7D%2C\"asyncParams\"%3A%7B\"tid\"%3A9381%7D%7D%7D";
                string strrtn = GetRequest(link);
                //问财在返回 extra的时候 带"{}"导致出错
                var begin = strrtn.IndexOf("\"extra\":\"{", StringComparison.Ordinal);
                if (begin != -1)
                {
                    var end = strrtn.IndexOf("}\"", StringComparison.Ordinal) + 3;
                    strrtn = strrtn.Remove(begin, end - begin);
                }
                //JObject o = JObject.Parse(strrtn);
                //var tt = o["data"];
                var xdx = JsonToObject<Root11656>(strrtn);
                if (xdx.data == null) return new List<RtnCloseReason>();
                var rtn = new List<RtnCloseReason>();
                foreach (var kk in xdx.data.data.result.reasons)
                {
                    rtn.Add(new RtnCloseReason
                    {
                        Stkcode = stockid,
                        SiteTime = DateTime.Parse(date),
                        Detial = RemoveHtmlTag(kk.@abstract),
                        Keyword = kk.word ?? "",
                        Link = kk.url,
                        Title = RemoveHtmlTag(kk.title),
                        Type = 1,
                        CrawlingTime = DateTime.Now
                    });
                }
                return rtn;
            }
            catch (Exception ex)
            {
                Log.Info(ex.Message);
                return null;
            }
        }



        private static string GetRequest(string str)
        {
            string tt = "";
            int fail = 0;
            try
            {
                bool canrtn;
                for (int i = 0; i < 5; i++)
                {
                    if (cookie == "")
                        GetCookieBySta();
                    HttpWebRequest request;
                    // 创建一个HTTP请求
                    request = (HttpWebRequest)WebRequest.Create(str);
                    SetHeaderValue(request.Headers, "Accept", "application/json");
                    SetHeaderValue(request.Headers, "Accept-Encoding", "gzip, deflate");
                    SetHeaderValue(request.Headers, "Accept-Language", "zh-CN,zh;q=0.9");
                    SetHeaderValue(request.Headers, "Connection", "keep-alive");
                    SetHeaderValue(request.Headers, "Cookie", cookie);
                    SetHeaderValue(request.Headers, "Host", "www.iwencai.com");
                    SetHeaderValue(request.Headers, "Referer", str);
                    SetHeaderValue(request.Headers, "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36");
                    SetHeaderValue(request.Headers, "X-Requested-With:", "XMLHttpRequest");
                    var response = (HttpWebResponse)(request.GetResponse());
                    request.KeepAlive = false;
                    var xx = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress);
                    System.IO.StreamReader myreader = new System.IO.StreamReader(xx, Encoding.GetEncoding("UTF-8"));
                    string responseText = myreader.ReadToEnd();
                    myreader.Close();
                    request.Abort();
                    tt = Unicode2String(responseText);
                    if (tt.StartsWith("<html><body>") || tt == "") GetCookieBySta();
                    else return tt;
                }
                return "Error";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }

        }

        public static void GetCookieBySta()
        {
            Thread tread = new Thread(new ParameterizedThreadStart(GetDynamicCookid));
            tread.SetApartmentState(ApartmentState.STA);
            tread.Start("http://www.iwencai.com");
            tread.Join();
        }

        public static void GetDynamicCookid(object obj)
        {
            string url = "http://www.iwencai.com";
            SetFeatureBrowserEmulation();
            var html = "";
            var computerid = "";
            var webForm = new Form
            {
                WindowState = FormWindowState.Minimized,
                Visible = false,
                ShowInTaskbar = false
            };
            var webBrowser = new WebBrowser();
            webForm.Controls.Add(webBrowser);
            //SetFeatureBrowserEmulation();
            webForm.Load += async (s, e) =>
            {
                try
                {
                    var cts = new CancellationTokenSource(1000 * 60); // cancel in 60s
                    html = await LoadDynamicPage(webBrowser, url, cts.Token);
                    if (webBrowser.Document != null) computerid = webBrowser.Document.Cookie;
                    webForm.Close();
                    webForm = null;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    if (webForm != null)
                    {
                        webForm.Close();
                        webForm = null;
                    }
                }
            };

            Application.Run(webForm);
            cookie = computerid;
            //cookie = computerid.Split(';')[1].Substring(12);
        }
        private static async Task<string> LoadDynamicPage(WebBrowser webBrowser, string url, CancellationToken token)
        {
            // navigate and await DocumentCompleted
            var tcs = new TaskCompletionSource<bool>();
            WebBrowserDocumentCompletedEventHandler handler = (s, arg) =>
                tcs.TrySetResult(true);

            using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true))
            {
                webBrowser.DocumentCompleted += handler;
                try
                {
                    webBrowser.Navigate(url);
                    await tcs.Task; // wait for DocumentCompleted
                }
                finally
                {
                    webBrowser.DocumentCompleted -= handler;
                }
            }

            // get the root element
            var documentElement = webBrowser.Document.GetElementsByTagName("html")[0];

            // poll the current HTML for changes asynchronosly
            var html = documentElement.OuterHtml;
            while (true)
            {
                // wait asynchronously, this will throw if cancellation requested
                await Task.Delay(500, token);

                // continue polling if the WebBrowser is still busy
                if (webBrowser.IsBusy)
                    continue;

                var htmlNow = documentElement.OuterHtml;
                if (html == htmlNow)
                    break; // no changes detected, end the poll loop

                html = htmlNow;
            }

            // consider the page fully rendered 
            token.ThrowIfCancellationRequested();
            return html;
        }
        public static void SetFeatureBrowserEmulation()
        {
            if (LicenseManager.UsageMode != LicenseUsageMode.Runtime)
                return;
            var appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
            //Registry.SetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION",
            //    appName, 10000, RegistryValueKind.DWord);
            Registry.SetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION",
    appName, 11000, RegistryValueKind.DWord);
        }



        private static void SetHeaderValue(WebHeaderCollection header, string name, string value)
        {
            var property = typeof(WebHeaderCollection).GetProperty("InnerCollection",
                System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            if (property != null)
            {
                var collection = property.GetValue(header, null) as NameValueCollection;
                collection[name] = value;
            }
        }

        private static string RemoveHtmlTag(string htmlstr)
        {
            string reg = @"[<].*?[>]";
            return Regex.Replace(htmlstr, reg, "");
        }

        private static string Unicode2String(string source)
        {
            return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase | RegexOptions.Compiled).Replace(
                source, x => string.Empty + Convert.ToChar(Convert.ToUInt16(x.Result("$1"), 16)));
        }

        private static string ObjectToJson<T>(T obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        private static T JsonToObject<T>(string json)
        {
            if (json == null)
                json = ObjectToJson(default(T));
            return JsonConvert.DeserializeObject<T>(json);
        }
    }

    #region Json 11656  多个原因

    public class Result
    {
        /// <summary>
        /// 
        /// </summary>
        public int ydType { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string ydTypeName { get; set; }

        /// <summary>
        /// 涨停原因分析
        /// </summary>
        public string ydTypeText { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string dateFormated { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public List<ReasonsItem> reasons { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string agreeUrlTpl { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string disagreeUrlTpl { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string disagreeContentUrl { get; set; }

        /// <summary>
        /// 原因
        /// </summary>
        public string reasowWord { get; set; }
    }

    public class ReasonsItem
    {
        /// <summary>
        /// 
        /// </summary>
        public int id { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string uid { get; set; }

        /// <summary>
        /// 光环新网预计一季度净利润同比增长51%至75%
        /// </summary>
        public string title { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string pubtime { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string url { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string date { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string article_type { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string stock_code { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int yd_type { get; set; }

        /// <summary>
        /// 业绩增长
        /// </summary>
        public string word { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string word_cat { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int word_authority { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int word_id { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string @operator { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string api { get; set; }

        /// <summary>
        /// 
        /// </summary>
        // public string extra { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public int sort { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string expire_date { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string created { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string updated { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int effecive_period { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int effecive_period_rest { get; set; }

        /// <summary>
        /// 业绩
        /// </summary>
        public string wordI { get; set; }

        /// <summary>
        /// 公司业绩
        /// </summary>
        public string wordII { get; set; }

        /// <summary>
        /// 业绩增长
        /// </summary>
        public string wordIII { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string article_order { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string api_tag { get; set; }

        /// <summary>
        /// 有效期内
        /// </summary>
        public string category { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string priority { get; set; }

        /// <summary>
        /// 公司预计2018年1-3月归属上市公司股东的净利润1.30亿至1.50亿，同比变动51.47%至74.78%，计算机应用行业平均净利润增长率为2.61%。
        /// </summary>
        public string @abstract { get; set; }

        /// <summary>
        /// 同花顺原创
        /// </summary>
        public string source { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int agreeCount { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public int disagreeCount { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string voted { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string date_en { get; set; }

        /// <summary>
        /// 2018年03月16日
        /// </summary>
        public string date_ch { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string show_url { get; set; }

        /// <summary>
        /// 
        /// </summary>
    }

    public class PraiseInfo11656
    {
        /// <summary>
        /// 
        /// </summary>
        public string praise { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string usefulTotal { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string uselessTotal { get; set; }
    }

    public class Data11656_1
    {
        /// <summary>
        /// 
        /// </summary>
        public Result result { get; set; }

        /// <summary>
        /// 涨停揭秘
        /// </summary>
        public string block_title { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public PraiseInfo11656 praiseInfo { get; set; }
    }

    public class Data11656
    {
        /// <summary>
        /// 
        /// </summary>
        public string show_type { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public Data11656_1 data { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string pid { get; set; }

        /// <summary>
        /// 涨停揭秘
        /// </summary>
        public string title { get; set; }
    }

    public class Root11656
    {
        /// <summary>
        /// 
        /// </summary>
        public string success { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string message { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public Data11656 data { get; set; }
    }

    #endregion

    #region 单个原因 主要用于回补

    public class Detail
    {
        public string title { get; set; }
        public string @abstract { get; set; }
        public string url { get; set; }
    }

    public class ResultItem
    {
        /// <summary>
        /// 
        /// </summary>
        public string @char { get; set; }

        /// <summary>
        /// 区块链+游戏
        /// </summary>
        public string keyword { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string value { get; set; }

        /// <summary>
        /// 600652 2018-01-09 涨停原因
        /// </summary>
        public string w { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public Detail detail { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string detailApi { get; set; }
    }

    public class PraiseInfo
    {
        /// <summary>
        /// 
        /// </summary>
        public string praise { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string usefulTotal { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string uselessTotal { get; set; }
    }

    public class Data
    {
        public string block_title { get; set; }
        public List<ResultItem> result { get; set; }
        public string start_date { get; set; }
        public string end_date { get; set; }
        public string chart_title { get; set; }
        public string label_title { get; set; }
        public string label_exists { get; set; }
        public string detail_exists { get; set; }
        public string detail_type { get; set; }
        public string related_topic { get; set; }
        public PraiseInfo praiseInfo { get; set; }
    }

    public class TempData
    {
        public string show_type { get; set; }
        public Data data { get; set; }
        public string pid { get; set; }
        public string title { get; set; }
    }

    public class Root
    {
        /// <summary>
        /// 
        /// </summary>
        public string success { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string message { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public TempData data { get; set; }
    }


    public class Rootreason
    {
        /// <summary>
        /// 
        /// </summary>
        public string success { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string message { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public Detail data { get; set; }
    }

    #endregion
}